package org.opens.netty.chatServer.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.opens.netty.chatServer.protocol.MessageCodecSharable;
import org.opens.netty.chatServer.protocol.ProtocolFrameDecoder;
import org.opens.netty.chatServer.server.handle.*;

@Slf4j
public class ChatServer {

    public static void main(String[] args) {
        NioEventLoopGroup bossEventLoopGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerEventLoopGroup = new NioEventLoopGroup();

        LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
        MessageCodecSharable MESSAGE_CODEC_SHARABLE = new MessageCodecSharable();

        LoginRequestMessageHandler loginRequestMessageHandler = new LoginRequestMessageHandler();
        ChatRequestMessageHandle chatRequestMessageHandle = new ChatRequestMessageHandle();
        GroupCreateRequestMessageHandle groupCreateRequestMessageHandle = new GroupCreateRequestMessageHandle();
        GroupChatRequestMessageHandle groupChatRequestMessageHandle = new GroupChatRequestMessageHandle();
        GroupJoinRequestMessageHandle groupJoinRequestMessageHandle = new GroupJoinRequestMessageHandle();
        GroupMembersRequestMessageHandle groupMembersRequestMessageHandle = new GroupMembersRequestMessageHandle();
        GroupQuitRequestMessageHandle groupQuitRequestMessageHandle = new GroupQuitRequestMessageHandle();

        QuitHandle quitHandle = new QuitHandle();
        RpcRequestHandle rpcRequestHandle = new RpcRequestHandle();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.group(bossEventLoopGroup, workerEventLoopGroup);
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                /**
                 * 会在连接channel建立成功后触发这个方法
                 */
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new ProtocolFrameDecoder());
                    ch.pipeline().addLast(LOGGING_HANDLER);
                    ch.pipeline().addLast(MESSAGE_CODEC_SHARABLE);
                    // 参数1: 若干秒内没有收到client发来的数据就会触发一个事件-{@link IdleState#READER_IDLE}; 参数2: 若干秒内没有向channel写入数据就认为空闲了; 参数3: 若干秒内没有发生任何读写事件
                    ch.pipeline().addLast(new IdleStateHandler(5, 0, 0));
                    // ChannelDuplexHandler可以同时作为入站处理器和出站处理器
                    ch.pipeline().addLast(new ChannelDuplexHandler() {
                        /**
                         * 用来处理特殊事件, 比如说IdleState#READER_IDLE
                         */
                        @Override
                        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                            IdleStateEvent event = (IdleStateEvent) evt;
                            // 判断事件类型
                            if (event.state() == IdleState.READER_IDLE) {
                                log.info("已经5秒没有读取到数据了");
                            }
                        }
                    });
                    // MESSAGE_CODEC_SHARABLE这个handle可以解析出多种类型的消息, 也就是Message的子类
                    ch.pipeline().addLast(loginRequestMessageHandler);
                    ch.pipeline().addLast(chatRequestMessageHandle);
                    ch.pipeline().addLast(groupCreateRequestMessageHandle);
                    ch.pipeline().addLast(groupChatRequestMessageHandle);
                    ch.pipeline().addLast(groupJoinRequestMessageHandle);
                    ch.pipeline().addLast(groupMembersRequestMessageHandle);
                    ch.pipeline().addLast(groupQuitRequestMessageHandle);
                    ch.pipeline().addLast(quitHandle);
                    ch.pipeline().addLast(rpcRequestHandle);
                }
            });
            ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("server error: ", e);
        } finally {
            bossEventLoopGroup.shutdownGracefully();
            workerEventLoopGroup.shutdownGracefully();
        }
    }

}
